﻿using System;
using System.Configuration;
using System.Diagnostics;
using System.ServiceModel;
using System.ServiceModel.Dispatcher;
using System.Text;
using System.ServiceModel.Channels;
using Cherry.Agile.ServiceModel;

namespace Cherry.Agile.ServiceModel.Interceptor
{
    /// <summary>
    /// 
    /// </summary>
    public class OperationInvoker : IOperationInvoker
    {

        #region events
        /// <summary>
        /// 预调用事件
        /// </summary>
        public static event EventHandler<PreInvokeEventArgs> PreInvok;

        /// <summary>
        /// 调用结束事件
        /// </summary>
        public static event EventHandler<PostInvokeEventArgs> PostInvoke;
        #endregion

        IOperationInvoker m_invoker;
        string m_operationMethod;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="invoker"><see cref="IOperationInvoker"/></param>
        /// <param name="operationMethod">方法名称</param>
        public OperationInvoker(IOperationInvoker invoker, string operationMethod )
        {
            Debug.Assert(invoker != null);
            m_invoker = invoker;
            
            this.m_operationMethod = operationMethod;
        }

        /// <summary>
        /// 返回参数对象的<see cref="System.Array"/>
        /// </summary>
        /// <returns></returns>
        public virtual object[] AllocateInputs()
        {
            return m_invoker.AllocateInputs();
        }

        /// <summary>
        /// 方法预调用事件触发
        /// </summary>
        /// <param name="instance">服务实例</param>
        /// <param name="inputs">调用参数</param>
        protected void OnPreInvoke(object instance, object[] inputs)
        {   
            if (PreInvok != null)
            {
                PreInvok(this, new PreInvokeEventArgs() { Inputs = inputs, OperationContractName = m_operationMethod });
            }
        }

        /// <summary>
        /// 方法调用结束事件触发
        /// </summary>
        /// <param name="instance">服务实例</param>
        /// <param name="returnedValue">方法调用结果</param>
        /// <param name="outputs">调用输出</param>
        /// <param name="err">调用异常信息</param>
        protected void OnPostInvoke(object instance, object returnedValue, object[] outputs, System.Exception err)
        {
            if (PostInvoke != null)
            {
                PostInvoke(this, new PostInvokeEventArgs() { Exception = err, Result = returnedValue, Outputs = outputs, OperationContractName = m_operationMethod });
            }
        }
        
        /// <summary>
        /// 同步调用方法
        /// </summary>
        /// <param name="instance">服务实例</param>
        /// <param name="inputs">调用输入参数</param>
        /// <param name="outputs">调用输出</param>
        /// <returns>方法调用结果</returns>
        public object Invoke(object instance, object[] inputs, out object[] outputs)
        {
            OnPreInvoke(instance, inputs);

            object returnedValue = null;
            object[] outputParams = new object[] { };
            try
            {
                
                returnedValue = m_invoker.Invoke(instance, inputs, out outputParams);

                PaginationProxyHandler.HandlerInputs(inputs);
                //ContextLifetimeManager.Clear();

                outputs = outputParams;
                OnPostInvoke(instance, returnedValue, null, null);
                return returnedValue;
            }
            catch (System.Exception ex)
            {
                outputs = outputParams;
                OnPostInvoke(instance, returnedValue, outputParams, ex);
                throw;
            }
        }

        /// <summary>
        /// 异步方法调用开始
        /// </summary>
        /// <param name="instance">服务实例</param>
        /// <param name="inputs">调用输入参数</param>
        /// <param name="callback">回调方法</param>
        /// <param name="state">异步上下文状态</param>
        /// <returns><see cref="IAsyncResult"/></returns>
        public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
        {
            OnPreInvoke(instance, inputs);
            return m_invoker.InvokeBegin(instance, inputs, callback, state);
        }

        /// <summary>
        /// 异步方法调用结束
        /// </summary>
        /// <param name="instance">服务实例</param>
        /// <param name="outputs">调用输出</param>
        /// <param name="result">异步调用的Result，<see cref="IAsyncResult"/></param>
        /// <returns>方法调用结果</returns>
        public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
        {
            object returnedValue = null;
            object[] outputParams = { };
            try
            {
                returnedValue = m_invoker.InvokeEnd(instance, out outputs, result);
                outputs = outputParams;
                return returnedValue;
            }
            catch (Exception ex)
            {
                outputs = null;
                OnPostInvoke(instance, returnedValue, outputParams, ex);
                throw;
                
            }
        }

        /// <summary>
        /// 是否是异步调用
        /// </summary>
        public bool IsSynchronous
        {
            get
            {
                return m_invoker.IsSynchronous;
            }
        }
    }

    /// <summary>
    /// 方法预调用事件参数
    /// </summary>
    public class PreInvokeEventArgs : EventArgs
    {
        /// <summary>
        /// Operation Contract 名称
        /// </summary>
        public string OperationContractName { get; set; }

        /// <summary>
        /// 方法调用的参数
        /// </summary>
        public object[] Inputs { get; internal set; }
    }

    /// <summary>
    /// 方法调用完毕事件参数
    /// </summary>
    public class PostInvokeEventArgs:EventArgs
    {
        /// <summary>
        /// Operation Contract 名称
        /// </summary>
        public string OperationContractName { get; internal set; }

        /// <summary>
        /// 方法调用结果
        /// </summary>
        public object Result { get; internal set; }

        /// <summary>
        /// 方法调用输出
        /// </summary>
        public object[] Outputs { get; internal set; }

        /// <summary>
        /// 方法调用中产生的异常信息
        /// </summary>
        public Exception Exception { get; internal set; }

        /// <summary>
        /// 方法调用是否存在异常信息
        /// </summary>
        public bool HasError { get { return this.Exception != null; } }
    }
}
